use crate::error::{Error, Result, ErrorCode};


pub trait Read<'de> {
    fn peek(&self) -> Result<Option<u8>> ;
    fn next(&mut self) -> Result<Option<u8>>;
    fn discard(&mut self) ;
    fn byte_offset(&self) -> usize ;
    fn is_key_byte(&self, byte: u8) -> bool;

    //convert to utf8
    fn parse_to_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'de, 's, str>>;
    fn parse_to_slice<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference::<'de, 's, [u8]>>;

    fn parse_bytes_raw<'s, T, F>(&'s mut self, scratch: &'s mut Vec<u8>, result: F) -> Result<Reference<'de, 's, T>> 
    where 
        T: ?Sized + 's,
        F: for<'f> FnOnce(&'s Self, &'f [u8]) -> Result<&'f T>;
}


pub enum Reference<'b, 'c, T: ?Sized> {
    Borrowed(&'b T),
    Copied(&'c T),
}

use core::ops::Deref;
impl<'b, 'c, T> Deref for Reference<'b, 'c, T> 
where 
    T: ?Sized 
{
    type Target = T;
    fn deref(&self) ->  &Self::Target {
        match *self {
            Reference::Borrowed(b) => b,
            Reference::Copied(c) => c,
        }
    }
}



//common for trait object derived from Read
fn error<'de, R, T>(read: &R, reason: ErrorCode) -> Result<T>
where 
    R: Read<'de> + ?Sized
{
    Err(Error::syntax(reason, read.byte_offset()))
}

fn peek_or_eof<'de, R>(read: &R) -> Result<u8> 
where 
    R: Read<'de> + ?Sized
{
    match read.peek()? {
        Some(b) => Ok(b),
        None => error(read, ErrorCode::EofWhileParsingString),
    }
}





pub struct SliceRead<'de> {
    slice: &'de [u8],
    index: usize,
}

impl<'de> SliceRead<'de> {
    #[inline]
    pub fn new(slice: &'de [u8]) -> Self {
        Self {
            slice,
            index: 0_usize,
        }
    }

    #[inline] //for test 
    pub fn __parse_bytes(&mut self) -> Result<Vec<u8>> {
        let mut result = Vec::<u8>::new();
        match self.parse_bytes_raw(&mut result, |_, bytes| Ok(bytes)) ? {
            Reference::Borrowed(b) => Ok(Vec::<u8>::from(b)),
            Reference::Copied(_) => Ok(result),
        }
    }
 
    #[inline] //for test 
    pub fn __parse_string(&mut self) -> Result<String> {
        let mut result = Vec::<u8>::new();
        match self.parse_to_str(&mut result)? {
            Reference::Borrowed(b) => Ok(b.to_string()),
            Reference::Copied(c) => Ok(c.to_string()),
        }
    }
}


impl<'de> Read<'de> for SliceRead<'de> {
    // return : Eof => Ok(None) or _u8 => Ok(Some(_u8))
    #[inline]
    fn peek(&self) -> Result<Option<u8>>{
        Ok(if self.index < self.slice.len() {
            Some(self.slice[self.index])
        } else {
            None
        })
    }

    #[inline]
    fn next(&mut self) -> Result<Option<u8>> {
        Ok(if self.index < self.slice.len() {
            let ch = self.slice[self.index];
            self.index += 1;
            Some(ch)
        } else {
            None
        })
    }

    #[inline]
    fn discard(&mut self) {
        self.index += 1;
    }

    #[inline]
    fn byte_offset(&self) -> usize {
        self.index
    }

    #[inline]
    fn is_key_byte(&self, byte: u8) -> bool {
        !matches!(byte, b'=' | b',' | b'[' | b']' | b'{' | b'}')
    }

    #[inline]
    fn parse_to_str<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference<'de, 's, str>>{
        fn as_str<'de, 's, R: Read<'de>>(read: &R, slice: &'s [u8]) -> Result<&'s str> {
            std::str::from_utf8(slice).or_else(|_| error(read, ErrorCode::InvalidUtf8Encode))
        }
        self.parse_bytes_raw(scratch, as_str)
    }
    #[inline]
    fn parse_to_slice<'s>(&'s mut self, scratch: &'s mut Vec<u8>) -> Result<Reference::<'de, 's, [u8]>>{
        self.parse_bytes_raw(scratch, |_, bytes| Ok(bytes))
    }
    fn parse_bytes_raw<'s, T, F>(&'s mut self, scratch: &'s mut Vec<u8>, result: F) -> Result<Reference<'de, 's, T>> 
    where 
        T: ?Sized + 's,
        F: for<'f> FnOnce(&'s Self, &'f [u8]) -> Result<&'f T>,
    {
        let mut start = self.index;
        while self.index < self.slice.len() {
            let escaped = ESCAPE[self.slice[self.index] as usize];
            match escaped {
                ED => {
                    break;
                }
                BS => {
                    scratch.extend_from_slice(&self.slice[start..self.index]);
                    self.index += 1;
                        
                    let c = peek_or_eof(self)?; // eof -> return Err(..)
                    if ESCAPE[c as usize] != I_ {
                        scratch.push(c);
                        self.index += 1;
                    }
                    else {
                        return error(self, ErrorCode::InvalidEscape); // met unescaped char 
                    }

                    start = self.index;
                }
                ER => {
                    return error(self, ErrorCode::InvalidEscape);
                }
                _ => {
                    self.index += 1;
                }
            }
        }
        
        if scratch.is_empty() {
            let borrowed = &self.slice[start..self.index];
            result(self, borrowed).map(Reference::Borrowed)
            //Ok(Reference::Borrowed(borrowed))
        } else {
            scratch.extend_from_slice(&self.slice[start..self.index]);
            result(self, scratch).map(Reference::Copied)
            //Ok(Reference::Copied(scratch))
        }
    }

}

const ED: u8 = 0x04; // ,0x2C =0x3D ]0x5D }0x7D end char of string
const ER: u8 = 0x02; // [0x5B {0x7B
const BS: u8 = 0x01; //backslash 5C
const I_: u8 = 0x00; // allow unescaped
static ESCAPE: [u8; 256] = {
    [
        //   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // 0
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // 1
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, ED, I_, I_, I_, // 2
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, ED, I_, I_, // 3
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // 4
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, ER, BS, ED, I_, I_, // 5
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // 6
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, ER, I_, ED, I_, I_, // 7
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // 8
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // 9
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // A
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // B
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // C
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // D
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // E
        I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, I_, // F
    ]
};


#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn use_slice_reader() {
        let b = b"X01=Hello";
        let mut sr = SliceRead::new(b);
        assert_eq!(Some(b'X'), sr.peek().unwrap());

        assert_eq!(Some(b'X'), sr.next().unwrap());
        assert_eq!(Some(b'0'), sr.peek().unwrap());

        assert_eq!(Some(b'0'), sr.next().unwrap());
        assert_eq!(Some(b'1'), sr.peek().unwrap());

        sr.discard();
        assert_eq!(Some(b'='), sr.peek().unwrap());
    }
    #[test]
    fn parse_bytes() {
        { // string as end of string
        let mut sr = SliceRead::new(b"abcde");
        assert_eq!(&b"abcde"[..], sr.__parse_bytes().unwrap());
        }
        
        { // string end of  ,
        let mut sr = SliceRead::new(b"abc,X02");
        assert_eq!(&b"abc"[..], sr.__parse_bytes().unwrap());
        }
        { // string end of ]
        let mut sr = SliceRead::new(b"abc]de");
        assert_eq!(&b"abc"[..], sr.__parse_bytes().unwrap());
        }
        { // string end of  }
        let mut sr = SliceRead::new(b"abc}de");
        assert_eq!(&b"abc"[..], sr.__parse_bytes().unwrap());
        }
        { // string end of  } // for key
        let mut sr = SliceRead::new(b"X01=de");
        assert_eq!(&b"X01"[..], sr.__parse_bytes().unwrap());
        }

        { // string end of  [
        let mut sr = SliceRead::new(b"X01=[de");
        assert_eq!(&b"X01"[..], sr.__parse_bytes().unwrap());
        }
        { // string end of  [
        let mut sr = SliceRead::new(b"X01={X02");
        assert_eq!(&b"X01"[..], sr.__parse_bytes().unwrap());
        }
    }

    #[test]
    fn parse_bytes_with_escape(){
        // *******  Normal cases
        { // escape char => =
        let mut sr = SliceRead::new(b"abcd\\=");
        assert_eq!(&b"abcd="[..], sr.__parse_bytes().unwrap());
        }
        { // escape char => ,
        let mut sr = SliceRead::new(b"abcd\\,");
        assert_eq!(&b"abcd,"[..], sr.__parse_bytes().unwrap());
        }
        { // escape char => "["
        let mut sr = SliceRead::new(b"abcd\\[");
        assert_eq!(&b"abcd["[..], sr.__parse_bytes().unwrap());
        }
        { // escape char => "]"
        let mut sr = SliceRead::new(b"abcd\\]");
        assert_eq!(&b"abcd]"[..], sr.__parse_bytes().unwrap());
        }
        { // escape char => "{"
        let mut sr = SliceRead::new(b"abcd\\{");
        assert_eq!(&b"abcd{"[..], sr.__parse_bytes().unwrap());
        }
        { // escape char => "}"
        let mut sr = SliceRead::new(b"abcd\\}");
        assert_eq!(&b"abcd}"[..], sr.__parse_bytes().unwrap());
        }
        { // escape char => "\\"
        let mut sr = SliceRead::new(b"abcd\\\\");
        assert_eq!(&b"abcd\\"[..], sr.__parse_bytes().unwrap());
        }

        //****  Exceptional Cases
        { // illegal escape char 
        let mut sr = SliceRead::new(b"abcd\\a");
        assert!(sr.__parse_bytes()
            .is_err_and(|e| 
                *e.code() == ErrorCode::InvalidEscape
                && e.index() == 5
                )
            );
        }
        { // escape flag "\\" & met the end of line
        let mut sr = SliceRead::new(b"abcd\\");
        assert!(sr.__parse_bytes()
            .is_err_and(|e| 
                *e.code() == ErrorCode::EofWhileParsingString
                && e.index() == 5
                )
            );
        }
        { // not the end of string && but must to be escaped char  "{"
        let mut sr = SliceRead::new(b"abcd{");
        assert!(sr.__parse_bytes()
            .is_err_and(|e| 
                *e.code() == ErrorCode::InvalidEscape 
                && e.index() == 4
                )
            ); 
        }
        { // not the end of string && but must to be escaped char  "["
        let mut sr = SliceRead::new(b"abcd[");
        assert!(sr.__parse_bytes()
            .is_err_and(|e| 
                *e.code() == ErrorCode::InvalidEscape 
                && e.index() == 4
                )
            ); 
        }
    }
    #[test]
    fn use_reference(){
        let s = "String";
        let f = Reference::Borrowed(s);
        
        if let Reference::Borrowed(b) = f {
            assert_eq!(s, b);
        }
        assert_eq!(6, f.len());


        let f = Reference::Copied(s);
        if let Reference::Copied(c) = f {
            assert_eq!(s, c);
        }

    }

    #[test]
    fn parse_string(){
        let mut sr = SliceRead::new(b"X01");
        assert_eq!("X01", sr.__parse_string().unwrap());

        let mut sr = SliceRead::new(b"Hello");
        assert_eq!("Hello", sr.__parse_string().unwrap());

        let mut sr = SliceRead::new(b"X02");
        assert_eq!("X02", sr.__parse_string().unwrap());

        let mut sr = SliceRead::new(b"hahaha");
        assert_eq!("hahaha", sr.__parse_string().unwrap());
    }

}
